package svc

import (
	"blogcenter/internal/config"
	"blogcenter/internal/middleware"
	"blogcenter/internal/model"
	"blogcenter/internal/utils"
	"context"
	"fmt"
	"log"
	"time"

	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
	"github.com/zeromicro/go-queue/kq"
	"github.com/zeromicro/go-zero/core/stores/redis"
	"github.com/zeromicro/go-zero/rest"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type ServiceContext struct {
	Config         config.Config
	DB             *gorm.DB
	Redis          *redis.Redis
	Auth           rest.Middleware
	MinioClient    *minio.Client
	BlogModel      model.BlogModel
	TagModel       model.TagModel
	CommentModel   model.CommentModel // 实现完整接口的模型
	KafkaPusher    *kq.Pusher
	CommentBatcher *model.CommentBatcher // 添加批处理器
	GorseClient    *utils.GorseClient
	SearchClient   *utils.SearchClient
}

func NewServiceContext(c config.Config) *ServiceContext {
	// 1. 初始化数据库
	db, err := gorm.Open(mysql.Open(c.DB.DataSource), &gorm.Config{
		PrepareStmt: true, // 开启预编译语句
	})
	if err != nil {
		log.Fatal("数据库连接失败: ", err)
	}

	// 2. 自动迁移表结构
	if err := migrateTables(db); err != nil {
		log.Fatal("数据库迁移失败: ", err)
	}

	// 3. 初始化Redis
	rds := redis.MustNewRedis(redis.RedisConf{
		Host: c.Redis.Host,
		Pass: c.Redis.Pass,
		Tls:  c.Redis.Tls,
		Type: c.Redis.Type,
	})

	// 4. 初始化Minio
	minioClient := initMinio(c)

	// 5. 初始化Kafka生产者
	kafkaPusher := kq.NewPusher(
		c.Kafka.Pusher.Brokers,
		c.Kafka.Pusher.Topic,
		kq.WithChunkSize(1000),
		kq.WithFlushInterval(5*time.Second),
	)

	// 6. 初始化模型和批处理器
	commentModel := model.NewCommentModel(db)
	batcher := model.NewCommentBatcher(commentModel)
	go batcher.Start() // 启动批处理协程

	cfg := config.GetBaseConfig()
	searchClient, err := utils.NewSearchClient(cfg.Consul.Host)
	if err != nil {
		log.Fatal("初始化 search 客户端失败: ", err)
	}

	return &ServiceContext{
		Config:         c,
		DB:             db,
		Redis:          rds,
		Auth:           middleware.NewAuthMiddleware(c.JWT.AccessSecret),
		MinioClient:    minioClient,
		BlogModel:      model.NewBlogModel(db),
		TagModel:       model.NewTagModel(db),
		CommentModel:   commentModel,
		KafkaPusher:    kafkaPusher,
		CommentBatcher: batcher,
		GorseClient:    utils.NewGorseClient(c.Gorse.Host, c.Gorse.ApiKey),
		SearchClient:   searchClient,
	}
}

// 辅助函数：数据库迁移
func migrateTables(db *gorm.DB) error {
	models := []interface{}{
		&model.BlogInfo{},
		&model.BlogImg{},
		&model.BlogTag{},
		&model.TagMap{},
		&model.BlogLike{},
		&model.CommentContent{},
		&model.CommentIndex{},
		&model.CommentSubject{},
		&model.CommentLike{},
	}

	return db.AutoMigrate(models...)
}

// 辅助函数：初始化Minio
func initMinio(c config.Config) *minio.Client {
	client, err := minio.New(c.Minio.Endpoint, &minio.Options{
		Creds:  credentials.NewStaticV4(c.Minio.AccessKey, c.Minio.SecretKey, ""),
		Secure: c.Minio.UseSSL,
	})
	if err != nil {
		panic(fmt.Errorf("初始化Minio失败: %v", err))
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	exists, err := client.BucketExists(ctx, c.Minio.BucketName)
	if err != nil {
		panic(fmt.Errorf("检查存储桶失败: %v", err))
	}

	if !exists {
		if err := client.MakeBucket(ctx, c.Minio.BucketName, minio.MakeBucketOptions{}); err != nil {
			panic(fmt.Errorf("创建存储桶失败: %v", err))
		}
	}

	return client
}
